package com.dps.recommend.utils;

import com.dps.recommend.beans.RecItemDps;
import com.google.common.collect.Lists;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 打散工具类
 *
 * @param
 */
public class DisperseUtils {


    /**
     * 根据类型相邻打散、最大化保留顺序
     *
     * @param itemList
     */
    public static <T extends RecItemDps> List<T> adjDisPer(List<T> itemList, int num) {
        if (CollectionUtils.isEmpty(itemList) || num < 0) {
            return itemList;
        }
        List<T> newItemList = new ArrayList<>(itemList.stream().filter(item -> !Objects.isNull(item) && !Objects.isNull(item.getType()) && !Objects.isNull(item.getItemId())).collect(Collectors.toList()));
        if (CollectionUtils.isEmpty(newItemList)) {
            return itemList;
        }

        if (num > newItemList.size()) {
            num = newItemList.size();
        }
        Set<String> itemIdSet = new HashSet<>();
        List<T> resultList = new ArrayList<>();
        String tmpType = ""; //标记类型
        for (int i = 0; i < newItemList.size() - 1 && resultList.size() < num; i++) {
            String type = newItemList.get(i).getType();
            String itemId = newItemList.get(i).getItemId();
            if (!itemIdSet.contains(itemId) && !type.equalsIgnoreCase(tmpType)) { //不包含，并且，当前类型不是上次的类型
                tmpType = type;
                itemIdSet.add(itemId);
                resultList.add(newItemList.get(i));
                for (int j = i + 1; j < newItemList.size() && resultList.size() < num; j++) {
                    String typeV2 = newItemList.get(j).getType();
                    String itemIdV2 = newItemList.get(j).getItemId();
                    if (!itemIdSet.contains(itemIdV2) && !typeV2.equalsIgnoreCase(tmpType)) { //不包含，并且，当前类型不是上次的类型
                        tmpType = typeV2;
                        itemIdSet.add(itemIdV2);
                        resultList.add(newItemList.get(j));
                        break;
                    }
                }
            }
        }

        if (resultList.size() < num) {
            List<T> addItemList = newItemList.stream().filter(rec -> !itemIdSet.contains(rec.getItemId())).limit(num - resultList.size()).collect(Collectors.toList());
            resultList.addAll(CollectionUtils.isEmpty(addItemList) ? Lists.newArrayList() : addItemList);
        }
        return resultList;
    }

    
    /**
     * 强制类型轮询、最大化保留顺序、类型天然散列
     *
     * @param itemList
     */
    public static <T extends RecItemDps> List<T> typeDisPer(List<T> itemList, int num) {
        if (CollectionUtils.isEmpty(itemList) || num < 0) {
            return itemList;
        }
        itemList = itemList.stream()
                .filter(item -> !Objects.isNull(item) && !Objects.isNull(item.getType()) && !Objects.isNull(item.getItemId()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(itemList)) {
            return itemList;
        }
        if (num > itemList.size()) {
            num = itemList.size();
        }

        LinkedHashMap<String, List<T>> typeMapList = itemList.stream().collect(Collectors.groupingBy(T::getType, LinkedHashMap::new, Collectors.toList()));
        if (CollectionUtils.isEmpty(typeMapList)) {
            return itemList.stream().limit(num).collect(Collectors.toList());
        }
        List<T> resultList = new ArrayList<>();
        List<String> ts = new ArrayList<>();
        ts.addAll(typeMapList.keySet());
        Set<String> itemIdSet = new HashSet<>();
        while (resultList.size() < num && !CollectionUtils.isEmpty(typeMapList)) {
            for (int i = 0; i < ts.size() && resultList.size() < num && !CollectionUtils.isEmpty(typeMapList); i++) {
                String type = ts.get(i);
                List<T> itemsList = typeMapList.get(type);
                if (!CollectionUtils.isEmpty(itemsList)) {
                    Optional<T> t = itemsList.stream().filter(item -> !itemIdSet.contains(item.getItemId())).filter(Objects::nonNull).findFirst();
                    if (!Objects.isNull(t) && t.isPresent() && !Objects.isNull(t.get())) {
                        T entity = t.get();
                        itemIdSet.add(entity.getItemId());
                        resultList.add(entity);
                        itemsList.remove(entity);
                    } else {
                        typeMapList.remove(type);
                    }
                } else {
                    typeMapList.remove(type);
                }
            }
        }

        if (CollectionUtils.isEmpty(resultList)) {
            return itemList.stream().limit(num).collect(Collectors.toList());
        }
        return resultList;
    }


}
